var TARIFF_SS_ID = "1R5798KFcnKrBnEuCJbgO3tHncJrx-OUEba12PVYkKgI";
var TARIFF_2016_SS_ID = "1OR2hRbSNXefHPVD2xEr_HdYe6PWMqsAxYB-ViI0VgNY";

/**
 * Lookup function for getting tariff column depending on organisation type.
 */
function tCol_(orgType) {
  if(orgType == ORG_TYPE_GGBUCKS) return 3;
  if(orgType == ORG_TYPE_GGUK) return 4;
  return 5;
}

function sSheet_(bookingDate) {
  if(bookingDate.getYear() == 2016) {
    return TARIFF_2016_SS_ID;
  }
  return TARIFF_SS_ID;
}

/**
 * Adds an invoice line to the invoice and recalculates totals.
 */
function addInvoiceLine_(invoice, desc, unitCost, quantity, totalCost) {
  invoice.lines.push({
      "lineID"      : invoice.lines.length + 1
    , "description" : desc
    , "unitCost"    : unitCost
    , "quantity"    : quantity
    , "totalCost"   : (unitCost * quantity)
  });
  
  // Recalculate totals
  invoice.total = invoice.total + (unitCost * quantity);
}

/**
 * Creates a new invoice structure.
 */
function newInvoice_() {
  return {
      "date"     : new Date()
    , "lines"    : []
    , "payments" : []
    , "total" : 0.00
    , "deposit" : {
          "amount" : 0.00
        , "dateDue" : new Date()
    }
    , "balance" : {
          "amount" : 0.00
        , "dateDue" : new Date()
    }
  };
}

/**
 * Calculates the invoice lines for a booking.
 */
function calculateBillingLines_(booking) {
  var bl2016 = booking.arrivalDate.getYear() == 2016;
  var ss = SpreadsheetApp.openById(sSheet_(booking.arrivalDate));
  
  // Create new invoice
  booking.invoice = newInvoice_();
  
  // Calculate headcount for booking
  var headCount = Number(booking.participants) + Number(booking.leaders);
  Logger.log("Head count: " + headCount);
  
  // Calculate number of nights
  var nights = booking.eventDays - 1;
  Logger.log("Nights: " + nights);
  
  // House booking
  if(booking.isHouseBooking) {
  
    // Residential booking
    if(nights > 0) {
      
      var tNights = nights;
      var xNights = 0;
      
      // Handle bookings longer than 7 nights
      if(tNights > 7) {
        xNights = tNights - 7;
        tNights = 7;
      }
      Logger.log("Billable nights: " + tNights + " (+" + xNights + ")");
      
      var tariffName = "House_Residential_Nights_" + tNights;
      Logger.log("Using tariff: " + tariffName);
      
      var pRate = 0.00;   // Rate per participant
      var xRate = 0.00;   // Rate per additional night
      var mCharge = 0.00; // Minimum charge
      
      // Lookup rates and minimum charge according to organisation type
      pRate = ss.getRangeByName(tariffName).getCell(1, tCol_(booking.organisation.type)).getValue();
      Logger.log("pRate: " + pRate);
      mCharge = ss.getRangeByName(tariffName).getCell(2, tCol_(booking.organisation.type)).getValue();
      Logger.log("Minimum charge: " + mCharge);
      xRate = ss.getRangeByName("House_Residential_AdditionalNights").getCell(1, tCol_(booking.organisation.type)).getValue();
      Logger.log("xRate: " + xRate);
      
      // Calculate accomodation cost
      var aCostPerHead = pRate + (xRate * xNights);
      var aCostTotal = aCostPerHead * headCount;
      addInvoiceLine_(booking.invoice, "House accommodation charge per person (" + nights + " nights)", aCostPerHead, headCount);
      
      // Add additional for minimum charge
      if(aCostTotal < mCharge) {
        var bCost = mCharge - aCostTotal;
        addInvoiceLine_(booking.invoice, "Minimum booking charge (" + nights + " nights)", bCost, 1);
      }
    
    } // End of residential booking lines
    
    // Day booking
    if(nights == 0) {
      
      // Lookup tariff based on event type and times
      var tariffName = [];
      if(booking.eventType == EVENT_TYPE_MEETING) {
        tariffName = ["House_DayUsage_NonPaying"];
      } else {
        if(booking.eventTime == EVENT_TIME_MORNING) {
          tariffName = ["House_DayUsage_Paying_Morning"];
        } else if(booking.eventTime == EVENT_TIME_AFTERNOON) {
          tariffName = ["House_DayUsage_Paying_Afternoon"];
        } else if(booking.eventTime == EVENT_TIME_EVENING) {
          tariffName = ["House_DayUsage_Paying_Evening"];
        } else if(booking.eventTime == EVENT_TIME_ALLDAY) {
          tariffName = ["House_DayUsage_Paying_AllDay"];
        } else if(booking.eventTime == EVENT_TIME_DAYTIME) {
          tariffName = ["House_DayUsage_Paying_Morning","House_DayUsage_Paying_Afternoon"];
        } else if(booking.eventTime == EVENT_TIME_LATEDAY) {
          tariffName = ["House_DayUsage_Paying_Afternoon","House_DayUsage_Paying_Evening"];
        }
        if(!bl2016) {
          if(booking.eventType == EVENT_TYPE_TRAINING) {
            tariffName = ["House_DayUsage_Paying"];
          } else if(booking.eventType == EVENT_TYPE_SOCIAL) {
            tariffName = ["House_DayUsage_Social"];
          }
        }
      }
      Logger.log("Using tariff: " + tariffName);
      
      var aCostTotal = 0;
      for(i= 0; i < tariffName.length; i ++) {
        // Lookup rates and minimum charge according to organisation type
        var pRate = ss.getRangeByName(tariffName[i]).getCell(1, tCol_(booking.organisation.type)).getValue();
        Logger.log("pRate: " + pRate);
      
        // Calculate usage cost
        aCostTotal += pRate;
      }
      addInvoiceLine_(booking.invoice, "House usage charge", aCostTotal, 1);
      
    } // End of day booking lines
    
    
  } // End of house booking lines
  
  // Field booking with equipent
  if(booking.isFieldBooking && booking.equipment.fullyEquipped) {
    
    // Residential booking
    if(nights > 0) {
      
      var tNights = nights;
      var xNights = 0;
      
      // Handle bookings longer than 7 nights
      if(tNights > 7) {
        xNights = tNights - 7;
        tNights = 7;
      }
      Logger.log("Billable nights: " + tNights + " (+" + xNights + ")");
      
      var tariffName = "CampSite_Equipped_Nights_" + tNights;
      Logger.log("Using tariff: " + tariffName);
      
      var pRate = 0.00;   // Rate per participant
      var xRate = 0.00;   // Rate per additional night
      var mCharge = 0.00; // Minimum charge
      
      // Lookup rates and minimum charge according to organisation type
      pRate = ss.getRangeByName(tariffName).getCell(1, tCol_(booking.organisation.type)).getValue();
      Logger.log("pRate: " + pRate);
      mCharge = ss.getRangeByName(tariffName).getCell(2, tCol_(booking.organisation.type)).getValue();
      Logger.log("Minimum charge: " + mCharge);
      xRate = ss.getRangeByName("CampSite_Equipped_AdditionalNights").getCell(1, tCol_(booking.organisation.type)).getValue();
      Logger.log("xRate: " + xRate);
      
      // Calculate accomodation cost
      var aCostPerHead = pRate + (xRate * xNights);
      var aCostTotal = aCostPerHead * headCount;
      addInvoiceLine_(booking.invoice, "Campsite usage charge per person (" + nights + " nights)", aCostPerHead, headCount);
      
      // Add additional for minimum charge
      if(aCostTotal < mCharge) {
        var bCost = mCharge - aCostTotal;
        addInvoiceLine_(booking.invoice, "Minimum booking charge (" + nights + " nights)", bCost, 1);
      }
      
    } // End of residential booking lines
    
    // Day booking
    if(nights == 0) {
      
      var tariffName = "CampSite_Equipped_DayHire";
      Logger.log("Using tariff: " + tariffName);
      
      // Lookup rates and minimum charge according to organisation type
      var pRate = ss.getRangeByName(tariffName).getCell(1, tCol_(booking.organisation.type)).getValue();
      Logger.log("pRate: " + pRate);
      
      // Calculate usage cost
      var aCostTotal = pRate;
      addInvoiceLine_(booking.invoice, "Campsite day hire", aCostTotal, 1);
      
      if(booking.equipment.tents > 0) {
      
        // Tent hire
        var tariffName = "CampSite_Equipped_TentHire";
        Logger.log("Using tariff: " + tariffName);
        
        // Lookup rates and minimum charge according to organisation type
        var tRate = ss.getRangeByName(tariffName).getCell(1, tCol_(booking.organisation.type)).getValue();
        Logger.log("tRate: " + tRate);
      
        // Calculate usage cost
        var tents = booking.equipment.tents;
        var tCostPerTent = tRate;
        var tCostTotal = tCostPerTent * tents;
        addInvoiceLine_(booking.invoice, "Tent hire", tCostPerTent, tents);
        
      } // End equipment hire
      
    } // End of day booking lines
    
    
  } // End of equipped field booking lines
  
  // Field booking without equipment
  if(booking.isFieldBooking && !booking.equipment.fullyEquipped) {
    
    // Residential booking
    if(nights > 0) {
      
      // Site hire
      var tariffName = "CampSite_Unequipped_SiteHire";
      Logger.log("Using tariff: " + tariffName);
      
      // Lookup rates and minimum charge according to organisation type
      var pRate = ss.getRangeByName(tariffName).getCell(1, tCol_(booking.organisation.type)).getValue();
      Logger.log("pRate: " + pRate);
      
      // Calculate usage cost
      var aCostPerHead = pRate;
      var aCostTotal = aCostPerHead * headCount * nights;
      addInvoiceLine_(booking.invoice, "Campsite usage charge per person per night", aCostPerHead, (headCount * nights));
      
      if(booking.equipment.tents > 0) {
      
        // Tent hire
        var tariffName = "CampSite_Unequipped_TentHire";
        Logger.log("Using tariff: " + tariffName);
        
        // Lookup rates and minimum charge according to organisation type
        var tRate = ss.getRangeByName(tariffName).getCell(1, tCol_(booking.organisation.type)).getValue();
        Logger.log("tRate: " + tRate);
      
        // Calculate usage cost
        var tents = booking.equipment.tents;
        var tCostPerTent = tRate;
        var tCostTotal = tCostPerTent * tents * nights;
        addInvoiceLine_(booking.invoice, "Tent hire per night", tCostPerTent, (tents * nights));
        
      } // End equipment hire
      
    } // End of residential booking lines
    
    // Day booking
    if(nights == 0) {
      
      var tariffName = [];
      if(booking.eventTime == EVENT_TIME_MORNING) {
        tariffName = ["CampSite_Unequipped_DayHire_Morning"];
      } else if(booking.eventTime == EVENT_TIME_AFTERNOON) {
        tariffName = ["CampSite_Unequipped_DayHire_Afternoon"];
      } else if(booking.eventTime == EVENT_TIME_EVENING) {
        tariffName = ["CampSite_Unequipped_DayHire_Evening"];
      } else if(booking.eventTime == EVENT_TIME_ALLDAY) {
        tariffName = ["House_DayUsage_Paying_AllDay"];
      } else if(booking.eventTime == EVENT_TIME_DAYTIME) {
        tariffName = ["CampSite_Unequipped_DayHire_Morning","CampSite_Unequipped_DayHire_Afternoon"];
      } else if(booking.eventTime == EVENT_TIME_LATEDAY) {
        tariffName = ["CampSite_Unequipped_DayHire_Afternoon","CampSite_Unequipped_DayHire_Evening"];
      }
      if(!bl2016) {
        tariffName = ["CampSite_Unequipped_DayHire"];
      }
      Logger.log("Using tariff: " + tariffName);
      
      var aCostTotal = 0;
      for(i = 0; i < tariffName.length; i ++) {
        // Lookup rates and minimum charge according to organisation type
        var pRate = ss.getRangeByName(tariffName).getCell(1, tCol_(booking.organisation.type)).getValue();
        Logger.log("pRate: " + pRate);
      
        // Calculate usage cost
        aCostTotal += pRate;
      }
      addInvoiceLine_(booking.invoice, "Campsite day hire", aCostTotal, 1);
      
      if(booking.equipment.tents > 0) {
      
        // Tent hire
        var tariffName = "CampSite_Unequipped_TentHire";
        Logger.log("Using tariff: " + tariffName);
        
        // Lookup rates and minimum charge according to organisation type
        var tRate = ss.getRangeByName(tariffName).getCell(1, tCol_(booking.organisation.type)).getValue();
        Logger.log("tRate: " + tRate);
      
        // Calculate usage cost
        var tents = booking.equipment.tents;
        var tCostPerTent = tRate;
        var tCostTotal = tCostPerTent * tents;
        addInvoiceLine_(booking.invoice, "Tent hire", tCostPerTent, tents);
        
      }
      
    } // End of day booking lines
    
  } // End of unequipped field booking lines
  
  Logger.log("Invoice total: " + booking.invoice.total);
  
}

/**
 * Calculates the payments required for the booking.
 */
function calculatePayments_(booking) {
  
  // Todays date
  var today = new Date();
  // Balance due date - 28 days before booking
  var balanceDue = new Date();
  balanceDue.setTime(booking.arrivalDate.getTime() - (28 * 86400 * 1000));
  
  // Calculate deposit amount
  var deposit = 0.0;
      
  // Check balance due date - if event is within 28 days full payment required
  if(balanceDue > today) {
    // Deposit is 50% of booking to a maximum of £60.
    deposit = Math.min(booking.invoice.total * 0.5, 60);
  }
      
  // Balance is remaining booking
  var balance = booking.invoice.total - deposit;
  
  booking.invoice.deposit.amount = deposit;
  booking.invoice.deposit.dateDue = today;
  Logger.log("Deposit payment: " + deposit);
      
  booking.invoice.balance.amount = balance;
  booking.invoice.balance.dateDue = balanceDue;
  Logger.log("Balance payment: " + balance);
  
}